package com.abel.bigwater.tlv.model

import io.netty.buffer.ByteBuf
import java.net.Inet4Address
import java.net.InetSocketAddress
import java.nio.charset.Charset
import java.time.LocalDateTime
import kotlin.experimental.and

data class TlvData3Terminal(
        var voltWarn: Int = 0,
        var maxFlowWarn: Long = 0,
        var maxFlowDuration: Short = 0,
        var serverIp: InetSocketAddress? = null,
        var rptPeriodStart: LocalDateTime? = null,
        var rptPeriodEnd: LocalDateTime? = null,
        var intervalMinutes: Short = 30,
        var rptFreqHours: Short = 24,
        var retryTimes: Short = 3,
        var retryMinutes: Short = 20,
        var sn: String? = null,
        var warnId: Int = 0,
        var apnInfo: ByteArray = ByteArray(10),
        var restore: Short = 0,
        var baseReading: Long = 0) : TlvData(TerminalParam.TAG) {

    override fun fill(buf: ByteBuf): ByteBuf {
        if (length == 0) finalLen()

        with(buf.alloc().buffer()) {
            writeByte(tag.toInt())
            writeShort(length)

            writeByte(TerminalParam.T0VoltWarn.id.toInt())
            writeShort(voltWarn)

            writeByte(TerminalParam.T1MaxFlowWarn.id.toInt())
            writeInt(maxFlowWarn.toInt())

            writeByte(TerminalParam.T2MaxFlowDuration.id.toInt())
            writeInt(maxFlowDuration.toInt())

            writeByte(TerminalParam.T3ServerIp.id.toInt())
            writeBytes(TlvHelper.toByteArray(serverIp!!))

            writeByte(TerminalParam.T4PeriodStart.id.toInt())
            writeBytes(TlvHelper.toByteArray(rptPeriodStart!!))

            writeByte(TerminalParam.T5PeriodEnd.id.toInt())
            writeBytes(TlvHelper.toByteArray(rptPeriodEnd!!))

            writeByte(TerminalParam.T6PeriodInterval.id.toInt())
            writeByte(intervalMinutes.toInt())

            writeByte(TerminalParam.T7PeriodFreq.id.toInt())
            writeByte(rptFreqHours.toInt())

            writeByte(TerminalParam.T8UpRetryTimes.id.toInt())
            writeByte(retryTimes.toInt())

            writeByte(TerminalParam.T9MaxRetryPeriod.id.toInt())
            writeByte(retryMinutes.toInt())

            val snBytes = sn?.take(16)?.toByteArray(Charsets.US_ASCII)
            if (snBytes!!.size != 16) throw IllegalArgumentException("BAD sn: ${sn}")
            writeByte(TerminalParam.TAAesKey.id.toInt())
            writeBytes(snBytes)

            writeByte(TerminalParam.TBWarnId.id.toInt())
            writeShort(warnId)

            if (apnInfo.size < 10) throw  IllegalArgumentException("NO enough size: ${apnInfo.size}")
            writeByte(TerminalParam.TCApnInfo.id.toInt())
            writeBytes(apnInfo.copyOf(10))

            writeByte(TerminalParam.TDReset.id.toInt())
            writeByte(restore.toInt())

            writeByte(TerminalParam.TEBaseReading.id.toInt())
            writeInt(baseReading.toInt())

            buf.writeBytes(this)
        }
        return buf
    }

    override fun parse(buf: ByteBuf): ByteBuf {
        try {
            super.parse(buf)
        } catch (ex: Exception) {
            log.error("FAIL to parse terminal caused by ${ex.message}", ex)
        }

        for (p1 in pieceList.orEmpty()) {
            when (p1.id) {
                TerminalParam.T0VoltWarn.id -> voltWarn = p1.readShort() and 0xFFFF
                TerminalParam.T1MaxFlowWarn.id -> maxFlowWarn = p1.readInt() and 0xFFFFFFFF
                TerminalParam.T2MaxFlowDuration.id -> maxFlowDuration = p1.readByte() and 0xFF

                TerminalParam.T3ServerIp.id -> {
                    val temp = buf.alloc().buffer()
                    temp.writeBytes(p1.value)
                    temp.skipBytes(4)

                    serverIp = InetSocketAddress(Inet4Address.getByAddress(p1.value!!.copyOf(4)),
                            temp.readShort().toInt() and 0xFFFF)
                }

                TerminalParam.T4PeriodStart.id -> rptPeriodStart = TlvHelper.toLocalDateTime(p1.value!!)

                TerminalParam.T5PeriodEnd.id -> rptPeriodEnd = TlvHelper.toLocalDateTime(p1.value!!)

                TerminalParam.T6PeriodInterval.id -> intervalMinutes = p1.readByte() and 0xFF

                TerminalParam.T7PeriodFreq.id -> rptFreqHours = p1.readByte() and 0xFF

                TerminalParam.T8UpRetryTimes.id -> retryTimes = p1.readByte() and 0xFF

                TerminalParam.T9MaxRetryPeriod.id -> retryMinutes = p1.readByte() and 0xFF

                TerminalParam.TAAesKey.id -> sn = String(p1.value!!, Charsets.US_ASCII)

                TerminalParam.TBWarnId.id -> warnId = p1.readShort() and 0xFFFF

                TerminalParam.TCApnInfo.id -> apnInfo = p1.value!!

                TerminalParam.TDReset.id -> restore = p1.readByte() and 0xFF

                TerminalParam.TEBaseReading.id -> baseReading = p1.readInt() and 0xFFFFFFFF
            }
        }

        return buf
    }
}